/*
 *  Copyright 2011 yura.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *  under the License.
 */
package org.opu.db_vdumper.ui.component.tabel.views;

import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.MouseEvent;
import java.awt.font.TextAttribute;
import java.util.HashMap;
import java.util.Map;
import javax.swing.UIManager;
import org.opu.db_vdumper.beans.ColumnBean;
import org.opu.db_vdumper.beans.TableBean;
import org.opu.db_vdumper.ui.component.tabel.TabelViewMethod;
import org.opu.db_vdumper.ui.component.tabel.models.ColumnModel;
import org.opu.db_vdumper.ui.component.tabel.models.SelectedComponentImpl;
import org.opu.db_vdumper.ui.component.tabel.models.TableModel;
import org.opu.db_vdumper.util.StringUtil;

/**
 *  Create instance of class using {@link TabelViewMethod}.
 * @author Potochnak Yana
 */
public class TableView extends SelectedComponentImpl {
    public static final int START_POSITION = 10;

    /** Data of current component */
    private TableModel model;
    private Font textFont;

    /**
     *  Create new instance
     * @param model Data of current component
     */
    public TableView(TableModel model) {
        this.model = model;
        model.addViews(TableView.this);
        //setToolTipText(model.getName());
    }

    /**
     *  Create new instance with {@link TableModel}
     * @param bean name of table in TabelModel
     */
    public TableView(TableBean bean) {
        this(new TableModel(bean));
    }

    /**
     *  Return position where attribute with specific name
     * @param attr attribute name
     * @return  position where attribute with specific name
     * @deprecated 
     */
    public int where(String attr){
        FontMetrics fm = getFontMetrix();
        int height = fm.getAscent();
        int hdraw = START_POSITION;
        int ident = START_POSITION;

        hdraw += height + ident;

        if (model.getSchema() != null) {
            hdraw += height + ident;
        }

        ColumnBean[] attributes = model.attributesArray();
        for (ColumnBean bean : attributes) {
            hdraw += height + ident;
            if (StringUtil.equals(bean.getName(), attr)){
                return hdraw - ident / 2;
            }
        }

        return fm.getAscent();
    }

    /**
     *  Return Model
     * @return Model
     */
    @Override
    public TableModel getViewModel() {
        return model;
    }

    /**
     *  Set Model
     * @param model Model
     */
    public void setModel(TableModel model) {
        this.model = model;
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);

        Font font = getTextFont();      //шрифт рисования
        Graphics2D g2 = (Graphics2D) g; //Графическое окружение для рисованя
        g2.setFont(font);               //устанавливаем шрифт рисования строк
        
        FontMetrics fm = g2.getFontMetrics(font);  //метрики шрифта
        int height = fm.getAscent();    //высота шрифта
        int wdraw = START_POSITION;     //позиция рисования по горизонтали
        int hdraw = START_POSITION + height; //позиция рисования по вертикали
        int mWidth = START_POSITION;    //максимальная ширена строки
        int ident = START_POSITION;     //вертикальный отступ
        int linePos ;   //место где рисовать линию отделяющую название и атрибуты

        // Рисуем строки
        mWidth = this.drawString(g2, model.getName(), hdraw, wdraw, mWidth, fm, false);
        hdraw += height + ident;

        if (model.getSchema() != null) {
            g2.setFont(new Font(font.getName(), Font.ITALIC + font.getStyle(), font.getSize()));
            mWidth = this.drawString(g2, model.getSchema(), hdraw, wdraw, mWidth, fm, false);
            hdraw += height + ident;
            g2.setFont(font);
        }
        
        linePos = hdraw - ident;
        hdraw += ident;

        for (ColumnModel cmodel : model.getColumns()) {
            ColumnBean bean = cmodel.getColumnBean();
            mWidth = this.drawString(g2, bean.getName() + ":" + bean.getTypeName(), 
            		hdraw, wdraw, mWidth, fm, model.isSelected() && !cmodel.isSelected());
            hdraw += height + ident;
            if (!cmodel.isSelected()){

            }
        }

        //Рисуем рамку
        drawBorder(g2, linePos);
    }

    /**
     *  Draw component border
     * @param g2 graphic environment
     * @param linePos where from start attribute (end header)
     */
    private void drawBorder(Graphics2D g2, int linePos) {
        Image toDraw = getImageBorder();
        Dimension s = getPreferredSize();

        //Рисуем обрамление (елсли оно есть)
        if (toDraw != null) {
            int step = toDraw.getWidth(null);

            g2.drawImage(toDraw, 0, 0, s.width, step, null);
            g2.drawImage(toDraw, 0, s.height - step, s.width, step, null);

            g2.drawImage(toDraw, 0, step, step, s.height - step * 2, null);
            g2.drawImage(toDraw, s.width - step, step, step, s.height - step * 2, null);
        }

        //Рисуем рамку
        g2.drawRect(2, 2, s.width - 5, s.height - 5);
        g2.drawLine(2, linePos, s.width - 4, linePos);
    }

    /**
     *  Draw string on graphic environment
     * @param g2  graphic environment
     * @param obj string thet drawing
     * @param hdraw  the x coordinate of the location where the
     *      String should be rendered
     * @param wdraw the y coordinate of the location where the
     *      String should be rendered
     * @param mWidth the maximum width of drawn string
     * @param fm font metrcis of current draw font, neded to
     *      determine drawn string width
     * @param strikethrough Draw or not horizontal line that is
     *      drawn through the text
     * @return if drawn string width great then mWidth, returned
     *      it`s widt, else returned mWidth
     */
    public int drawString(Graphics2D g2, String obj, int hdraw, int wdraw,
            int mWidth, FontMetrics fm, boolean strikethrough){
        if (obj != null){
            Font font = g2.getFont();
            if (strikethrough) {
                Map<TextAttribute, Object> map = new HashMap<TextAttribute, Object>();
                map.put(TextAttribute.STRIKETHROUGH, TextAttribute.STRIKETHROUGH_ON);
                g2.setFont(font.deriveFont(map));
            }
            g2.drawString(obj, wdraw, hdraw);
            if (strikethrough) {
                g2.setFont(font);
            }
            mWidth = strWidth(fm, obj, mWidth);
        }
        return mWidth;
    }

    /**
     *  If drawn obj width great then mWidth, returned it`s widt,
     * else returned mWidth
     * 
     * @param fm  font metrcis of current draw font, neded to
     *      determine drawn string width
     * @param obj string thet drawing
     * @param mWidth the maximum width of drawn string
     * @param fm font metrcis of current draw font, neded to
     * @return drawn obj width, if it great then mWidth,
     *      else returned mWidth
     */
    public int strWidth(FontMetrics fm, String obj, int mWidth) {
        int w = fm.stringWidth(obj);
        if (mWidth < w) {
            mWidth = w;
        }
        return mWidth;
    }

    @Override
    public Dimension getPreferredSize() {
        return this.calculateSize();//new Dimension(500,200);
    }

    @Override
    public void setLocation(Point p) {
        if (p.x < 1){
            p.x = 1;
        }
        if (p.y < 1){
            p.y = 1;
        }
        super.setLocation(p);
    }

    @Deprecated
    public String _getToolTipText(MouseEvent event) {
        int y = event.getY();

        FontMetrics fm = getFontMetrix();
        int height = fm.getAscent();
        int hdraw = START_POSITION;
        int ident = START_POSITION;
        hdraw += height + ident;

        if (y < hdraw){
            return model.getName();
        }

        if (model.getSchema() != null) {
            hdraw += height + ident;
            if (y < hdraw){
                return model.getSchema();
            }
        }

        ColumnBean[] attributes = model.attributesArray();
        for (ColumnBean bean : attributes) {
            hdraw += height + ident;
            if (y < hdraw){
                return bean.getName();
            }
        }
        
        return attributes[attributes.length - 1].getName();
    }

    /**
     *  Defines size of current component
     * @return  size of current component
     */
    private Dimension calculateSize(){
        FontMetrics fm = getFontMetrix();
        int height = fm.getAscent();
        int wdraw = START_POSITION;
        int hdraw = START_POSITION + height;
        int mWidth = START_POSITION;
        int ident = START_POSITION;

        mWidth = strWidth(fm, model.getName(), mWidth);
        hdraw += height + ident;

        if (model.getSchema() != null) {
            mWidth = strWidth(fm, model.getSchema(), mWidth);
            hdraw += height + ident;
        }
        hdraw += ident;

        ColumnBean[] attributes = model.attributesArray();
        for (ColumnBean bean : attributes) {
            mWidth = this.strWidth(fm, bean.getName() + ":" + bean.getTypeName(), mWidth);
            hdraw += height + ident;
        }

        mWidth = mWidth + wdraw * 2 + 2;
        
        return new Dimension(mWidth, hdraw);
    }

    /**
     *  Return the FontMetrics for the current Font.
     * @return FontMetrics for the current Font.
     */
    public FontMetrics getFontMetrix() {
        FontMetrics fm;
        Graphics graphics = getGraphics();
        if (graphics == null) {
            fm = Toolkit.getDefaultToolkit().getFontMetrics(getTextFont());
        } else {
            fm = graphics.getFontMetrics(getTextFont());
        }
        return fm;
    }

    public void setTextFont(Font textFont) {
        this.textFont = textFont;
    }

    public Font getTextFont() {
        if (textFont == null){
            return UIManager.getDefaults().getFont("Label.font");
        }
        return textFont;
    }

    @Override
    public void reset() {
        repaint();
    }
}
